Skip to content

fix(arcup): a release is newer than its own pre-release - #300

Open
JspIIV wants to merge 2 commits into
circlefin:mainfrom
JspIIV:fix/version-gt-release-beats-prerelease
Open

fix(arcup): a release is newer than its own pre-release#300
JspIIV wants to merge 2 commits into
circlefin:mainfrom
JspIIV:fix/version-gt-release-beats-prerelease

Conversation

@JspIIV

@JspIIV JspIIV commented Sep 1, 2026

Copy link
Copy Markdown

What

version_gt drops the pre-release tag from both arguments before it compares anything:

ver1="${ver1%%-*}"
ver2="${ver2%%-*}"

So 0.3.0 and 0.3.0-rc.1 both reduce to 0.3.0, every major/minor/patch comparison falls through, and the function reaches its final return 1. SemVer §11 puts a release above any pre-release of the same version, so this one should be true.

Measured against the current script:

call result expected
version_gt 0.3.1-rc.1 0.3.0 true true
version_gt 0.3.0-rc.1 0.3.0 false false
version_gt 0.3.0 0.3.0-rc.1 false true
version_gt 0.3.0 0.3.0-rc.2 false true

Why it matters

It affects anyone running a pre-release of the installer itself. check_installer_up_to_date never prints the "outdated" warning once the release ships, and update_arcup refuses to move:

if ! version_gt "$remote_version" "$ARCUP_INSTALLER_VERSION"; then

so arcup --self-update from 0.3.0-rc.1 to 0.3.0 reports that it is already current. There is no way out of an rc build except reinstalling by hand.

test_version_comparison covers the two cases that already worked and not this one, which is why it went unnoticed.

Change

Keep the pre-release tags aside instead of discarding them, and when major/minor/patch are equal treat an empty tag as the higher precedence.

Ordering two pre-releases of the same version (rc.2 vs rc.10) is deliberately left alone — it needs the full SemVer identifier comparison and no caller does it, since arcup only ever compares against its own version. Happy to add it if you would rather have it complete.

ARCUP_INSTALLER_VERSION bumped to 0.2.1, per the note at the top of the script.

Tests

Two cases added to test_version_comparison. Against main the first one fails:

ok - compares prerelease installer versions
ok - same prerelease base is not newer
not ok - release is newer than its prerelease

With the change, bash arcup/test_arcup.sh passes through to archive path traversal fails.

One note on running the suite locally: test_archive_link_entries_fail fails on a Windows checkout because ln -s needs privileges there. It fails the same way on an untouched tree, so it is unrelated to this change — I could not exercise that case or the two after it.

Closes #205.

version_gt strips the pre-release tag from both arguments before comparing,
so 0.3.0 and 0.3.0-rc.1 reduce to the same numbers, fall through every
comparison and reach the final `return 1`. SemVer orders a release above any
pre-release of the same version, so the answer should be true.

The effect is on anyone running a pre-release of the installer.
check_installer_up_to_date never tells them the release shipped, and
update_arcup refuses to move:

    if ! version_gt "$remote_version" "$ARCUP_INSTALLER_VERSION"; then

so `arcup --self-update` from 0.3.0-rc.1 to 0.3.0 reports it is already
current. The existing tests cover the two cases that already worked and not
this one.

Keep the pre-release tags aside and, when major.minor.patch are equal, treat
an empty tag as the higher precedence. Ordering two pre-releases of the same
version is left alone, since no caller compares them.

Installer version bumped per the note at the top of the script.
@romac romac added pending-import Merged PR awaiting reverse-sync to upstream and removed pending-import Merged PR awaiting reverse-sync to upstream labels Sep 1, 2026
@JspIIV

JspIIV commented Sep 1, 2026

Copy link
Copy Markdown
Author

The red Rust Integration Tests job here is #298, not this change.

Same test, same signal:

SIGKILL [11.466s] (11/13) arc-test-integration::basic validators_and_full_nodes_reach_height_3
(test aborted with signal 9: SIGKILL)
Summary [70.519s] 11/13 tests run: 10 passed, 1 failed, 0 skipped

which matches the report in #298 that the job is red on unrelated branches including sync/v0_8_0.

This PR touches arcup/arcup and arcup/test_arcup.sh only, so it has no path to the consensus integration suite. Every other check is green.

Worth noting alongside #248 — the arcup shell suite is not run in CI, so the two cases added here would not be exercised there either until that lands.

@osr21

osr21 commented Sep 1, 2026

Copy link
Copy Markdown

Confirming the CI attribution from the #298 side (I filed the job-level history analysis there): the only failing check on this head is Rust Integration Tests (Public CI run 33482375784) — every other check is green — and the quoted signature (SIGKILL on validators_and_full_nodes_reach_height_3, 11/13 run) is exactly the marginal OOM pattern documented in #298, which reproduces on unrelated branches including sync/v0_8_0. A shell-only change to arcup/arcup and arcup/test_arcup.sh has no path into the consensus integration suite, so the red job carries no signal about this PR.

I also ran the parts your Windows checkout couldn't. On Linux at head 54236e5, bash arcup/test_arcup.sh passes 27/27, exit 0 — including archive link entries fail and install_binary rejects symlink, the two cases after the traversal test that ln -s privileges blocked for you. For completeness I ran the suite on untouched main too (25/25 — so the two new assertions are the only behavioral delta in the suite).

Verification of the fix itself, from sourcing version_gt directly:

  • On main, the table in the PR body reproduces verbatim — 0.3.0 vs 0.3.0-rc.1 and 0.3.0-rc.2 both come back false.
  • With the patch: 0.3.0 > 0.3.0-rc.1 ✔, v0.3.0 > v0.3.0-rc.2 ✔, and the edge semantics hold — 0.3.0-rc.1 > 0.3.0 stays false, two pre-releases of the same base are unordered in both directions (rc.2 vs rc.1 → false, as the comment documents), and identical strings stay false via the early equality return. The deliberate scope cut is sound: the only call sites (check_installer_up_to_date, update_arcup) compare a remote version against the installer's own, so full SemVer identifier ordering has no caller today.

And confirmed on the #248 point: no workflow references arcup anywhere under .github/workflows/, so the two assertions added here will not run in CI until #248 lands — this PR is a concrete example of what that gap costs, since the missing case would have been caught the day a CI-run suite covered it.

@romac

romac commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@JspIIV Thanks! Can you please merge latest main into this branch?

@JspIIV

JspIIV commented Sep 2, 2026

Copy link
Copy Markdown
Author

Done — main merged in at c6f48d9, signed. The merge touched crates/malachite-app, crates/test/integration, deployments/ and docs/ only, so nothing in arcup/ moved.

Re-ran the shell suite on the merged head:

ok - compares prerelease installer versions
ok - same prerelease base is not newer
ok - release is newer than its prerelease
ok - release is newer than its prerelease with v prefix

The last two are the cases this PR adds; the first two are the ones that already passed.

@kutluhaneth46

Copy link
Copy Markdown

The direction is right for #205's headline case (0.3.0 > 0.3.0-rc.1), but this does not fully fix the issue as filed.

After cores match, the new branch only special-cases "stable vs any prerelease". Two prereleases of the same core still fall through to return 1, because the old ver1="${ver1%%-*}" strip remains:

version_gt "0.3.0-rc.2" "0.3.0-rc.1"  # still false — #205 explicitly expects true
version_gt "1.0.0-beta.11" "1.0.0-beta.2"  # still false

#205's expected behaviour and checklist both require SemVer §11 identifier ordering, not only "release beats its own RC".

Also overlaps with #212, which already implements full §11 precedence (build-metadata strip, numeric vs alphanumeric identifiers, dedicated arcup/version_gt_test.sh). Suggest closing this in favour of #212, or expanding this PR to that bar — otherwise maintainers still have an incomplete version_gt if this lands first.

The ARCUP_INSTALLER_VERSION bump to 0.2.1 is correct and necessary for self-update to deliver any version_gt fix.

@osr21

osr21 commented Sep 4, 2026

Copy link
Copy Markdown

@kutluhaneth46 Your behavioural claim is correct — I executed all three implementations rather than reading them, and the gap is exactly where you say it is:

call main #300 #212 #205 expects
version_gt 1.0.0 1.0.0-rc.1 false true true true
version_gt 1.0.0-rc.2 1.0.0-rc.1 false false true true
version_gt 1.0.0-beta.11 1.0.0-beta.2 false false true true
version_gt 1.0.0-rc.1 1.0.0 false false false false

And #205 does ask for those rows explicitly — both its "Example expected comparisons" block and its Tests checklist list 1.0.0-rc.2 > 1.0.0-rc.1 and 1.0.0-beta.11 > 1.0.0-beta.2. So "does not fully fix the issue as filed" is accurate, and #212 genuinely clears the bar: its own suite runs 25 passed, 0 failed, and arcup/test_arcup.sh still passes on that branch too.

Three things I'd check before acting on the close #300 in favour of #212 part, though.

1. #212 does not carry the version bump

You correctly flagged the ARCUP_INSTALLER_VERSION bump as "necessary for self-update to deliver any version_gt fix." By that same criterion:

main    ARCUP_INSTALLER_VERSION="0.2.0"
#300    ARCUP_INSTALLER_VERSION="0.2.1"
#212    ARCUP_INSTALLER_VERSION="0.2.0"   <- unchanged; no such line in its diff

Closing #300 for #212 as it stands would land the more complete algorithm behind a version number that self-update can't act on — the exact failure the bump exists to prevent. #212 needs the bump added before it substitutes for #300.

2. The two PRs conflict, so "if this lands first" is a rebase question

A real trial merge of #300 into #212 gives CONFLICT (content): Merge conflict in arcup/arcup — both rewrite the same version_gt body. So maintainers aren't choosing between "complete" and "incomplete version_gt persists"; whichever lands second needs a rebase regardless. That reframes the risk you're pointing at.

3. Relative state of the two PRs

#212 was last touched 2026-07-27 (head dbbd86b), has no formal review, and has sat five and a half weeks. #300 is active — romac asked for a main merge on Sep 2 and JspIIV delivered it at c6f48d9 two days ago. That doesn't make #300 more correct, but "close the active one in favour of the stale one" is worth weighing against the fact that #212 needs work (the bump) before it's a drop-in.

On reachability — correcting myself

Earlier in this thread I wrote that full identifier ordering "has no caller today." That was right by accident, and the reasoning behind it deserves tightening, because it bears on how urgent your point is.

Both call sites compare remote_version against the local ARCUP_INSTALLER_VERSION, and remote_version is scraped from:

ARCUP_BIN_URL="https://raw.githubusercontent.com/circlefin/arc-node/main/arcup/arcup"

That's raw main, not releases/latest — so the remote side is whatever main currently declares, with no structural guarantee it's a stable version. Checking the full history of that line, it has only ever held 0.0.1 and 0.2.0 (0.2.1 pending here), so a two-prerelease comparison has never actually occurred.

But that's a property of convention, not of construction. The accepted version regex explicitly permits prerelease suffixes ((-[A-Za-z0-9.+-]+)?), so the first time main declares an -rc, users on an earlier rc of the same core silently stop being offered updates. That's a point in favour of your position: the gap is dormant rather than absent, and completing it now is cheaper than discovering it during an rc.

Suggested path

Rather than closing #300, the lowest-friction resolution is probably for it to expand to full §11 — @JspIIV already offered exactly that ("Happy to add it if you would rather have it complete"), it already has the bump and maintainer momentum, and #212's implementation is available to borrow from with credit. The alternative — land #212 plus the version bump and close #300 — is equally fine, but it's strictly more work than it looks, not less.

One CI wrinkle either way

Per #248, no workflow under .github/workflows/ references arcup, so none of these assertions run in CI today. Worth noting that #212 adds a separate file, arcup/version_gt_test.sh, alongside the existing arcup/test_arcup.sh that #300 extends — so whichever lands, #248's wiring needs to pick up both files, not just the one.


All version comparisons above were executed on Linux against each branch's actual arcup (sourced with ARCUP_SKIP_MAIN=1), not inferred from reading the diffs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: arcup SemVer comparison treats prerelease and stable versions as equal

4 participants